<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lambda本地测试服务器</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: #f5f5f5;
            min-height: 100vh;
            padding: 20px;
            color: #333;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            overflow: hidden;
        }
        
        .header {
            background: #1e293b;
            color: white;
            padding: 20px;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        
        .header h1 {
            font-size: 1.8em;
            font-weight: 500;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .header h1 i {
            color: #f97316;
        }
        
        .header p {
            font-size: 0.9em;
            opacity: 0.8;
        }
        
        .content {
            padding: 20px;
            display: grid;
            grid-template-columns: 250px 1fr;
            gap: 20px;
        }
        
        .sidebar {
            background: #f8fafc;
            border-radius: 6px;
            padding: 15px;
            height: fit-content;
        }
        
        .sidebar-title {
            font-size: 1.1em;
            font-weight: 500;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 1px solid #e2e8f0;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .function-list {
            list-style: none;
            max-height: 400px;
            overflow-y: auto;
        }
        
        .function-item {
            padding: 8px 12px;
            border-radius: 4px;
            margin-bottom: 5px;
            cursor: pointer;
            transition: all 0.2s;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .function-item:hover {
            background: #e2e8f0;
        }
        
        .function-item.active {
            background: #1e293b;
            color: white;
        }
        
        .function-item i {
            font-size: 0.9em;
            color: #64748b;
        }
        
        .function-item.active i {
            color: #f97316;
        }
        
        .main-content {
            display: flex;
            flex-direction: column;
            gap: 20px;
        }
        
        .request-tabs {
            display: flex;
            border-bottom: 1px solid #e2e8f0;
        }
        
        .tab {
            padding: 10px 15px;
            cursor: pointer;
            border-bottom: 2px solid transparent;
            font-weight: 500;
            color: #64748b;
        }
        
        .tab.active {
            border-bottom-color: #1e293b;
            color: #1e293b;
        }
        
        .tab-content {
            display: none;
        }
        
        .tab-content.active {
            display: block;
        }
        
        .panel {
            background: white;
            border-radius: 6px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            padding: 15px;
        }
        
        .panel-title {
            font-size: 1em;
            font-weight: 500;
            margin-bottom: 15px;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        
        .panel-title button {
            background: none;
            border: none;
            color: #64748b;
            cursor: pointer;
            font-size: 0.9em;
        }
        
        .panel-title button:hover {
            color: #1e293b;
        }
        
        .form-group {
            margin-bottom: 15px;
        }
        
        .form-group label {
            display: block;
            margin-bottom: 5px;
            font-size: 0.9em;
            color: #64748b;
        }
        
        .form-control {
            width: 100%;
            padding: 8px 12px;
            border: 1px solid #e2e8f0;
            border-radius: 4px;
            font-size: 0.9em;
        }
        
        .form-control:focus {
            outline: none;
            border-color: #1e293b;
        }
        
        .key-value-table {
            width: 100%;
            border-collapse: collapse;
        }
        
        .key-value-table th {
            text-align: left;
            padding: 8px;
            font-size: 0.8em;
            color: #64748b;
            font-weight: normal;
            border-bottom: 1px solid #e2e8f0;
        }
        
        .key-value-table td {
            padding: 8px;
            border-bottom: 1px solid #f1f5f9;
        }
        
        .key-value-table input {
            width: 100%;
            padding: 6px 8px;
            border: 1px solid #e2e8f0;
            border-radius: 3px;
            font-size: 0.9em;
        }
        
        .key-value-table input:focus {
            outline: none;
            border-color: #1e293b;
        }
        
        .key-value-table button {
            background: none;
            border: none;
            color: #64748b;
            cursor: pointer;
        }
        
        .key-value-table button:hover {
            color: #dc2626;
        }
        
        .add-row-btn {
            margin-top: 10px;
            background: none;
            border: none;
            color: #1e293b;
            font-size: 0.9em;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 5px;
        }
        
        .json-editor {
            width: 100%;
            height: 200px;
            border: 1px solid #e2e8f0;
            border-radius: 4px;
            padding: 10px;
            font-family: 'Courier New', monospace;
            font-size: 0.9em;
            resize: vertical;
        }
        
        .json-editor:focus {
            outline: none;
            border-color: #1e293b;
        }
        
        .submit-btn {
            background: #1e293b;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            font-size: 0.9em;
            cursor: pointer;
            transition: all 0.2s;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .submit-btn:hover {
            background: #0f172a;
        }
        
        .response-container {
            margin-top: 20px;
        }
        
        .response-tabs {
            display: flex;
            border-bottom: 1px solid #e2e8f0;
        }
        
        .response-tab {
            padding: 8px 15px;
            cursor: pointer;
            border-bottom: 2px solid transparent;
            font-size: 0.9em;
            color: #64748b;
        }
        
        .response-tab.active {
            border-bottom-color: #1e293b;
            color: #1e293b;
        }
        
        .response-content {
            padding: 15px;
            background: #f8fafc;
            border-radius: 0 0 6px 6px;
            min-height: 200px;
            max-height: 400px;
            overflow-y: auto;
        }
        
        .response-body {
            font-family: 'Courier New', monospace;
            font-size: 0.9em;
            white-space: pre-wrap;
        }
        
        .status-badge {
            display: inline-block;
            padding: 3px 8px;
            border-radius: 3px;
            font-size: 0.8em;
            font-weight: 500;
            margin-bottom: 10px;
        }
        
        .status-success {
            background: #dcfce7;
            color: #166534;
        }
        
        .status-error {
            background: #fee2e2;
            color: #991b1b;
        }
        
        .history-list {
            list-style: none;
            max-height: 300px;
            overflow-y: auto;
        }
        
        .history-item {
            padding: 10px;
            border-bottom: 1px solid #e2e8f0;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .history-item:hover {
            background: #f1f5f9;
        }
        
        .history-method {
            font-size: 0.8em;
            padding: 3px 6px;
            border-radius: 3px;
            font-weight: 500;
        }
        
        .method-get {
            background: #dcfce7;
            color: #166534;
        }
        
        .method-post {
            background: #dbeafe;
            color: #1e40af;
        }
        
        .method-put {
            background: #fef3c7;
            color: #92400e;
        }
        
        .method-delete {
            background: #fee2e2;
            color: #991b1b;
        }
        
        .history-url {
            flex: 1;
            font-size: 0.9em;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        
        .history-time {
            font-size: 0.8em;
            color: #64748b;
        }
        
        .loading {
            display: none;
            text-align: center;
            padding: 30px;
        }
        
        .spinner {
            border: 3px solid rgba(0,0,0,0.1);
            border-radius: 50%;
            border-top-color: #1e293b;
            width: 24px;
            height: 24px;
            animation: spin 1s linear infinite;
            margin: 0 auto 10px;
        }
        
        @keyframes spin {
            to { transform: rotate(360deg); }
        }
        
        .no-functions {
            text-align: center;
            padding: 40px;
            color: #64748b;
        }
        
        .no-functions i {
            font-size: 2em;
            margin-bottom: 10px;
            color: #cbd5e1;
        }
        
        .clear-history {
            margin-top: 10px;
            text-align: right;
        }
        
        .clear-history button {
            background: none;
            border: none;
            color: #64748b;
            font-size: 0.8em;
            cursor: pointer;
        }
        
        .clear-history button:hover {
            color: #dc2626;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1><i class="fas fa-bolt"></i> Lambda本地测试服务器</h1>
            <p>测试您的Lambda函数，支持GET、POST、PUT、DELETE操作</p>
        </div>
        
        <div class="content">
            <div class="sidebar">
                <div class="sidebar-title">
                    <i class="fas fa-folder-open"></i> 函数列表
                </div>
                
                <ul class="function-list" id="functionList">
                    <!-- 函数列表将通过JavaScript动态加载 -->
                </ul>
                
                <div class="sidebar-title" style="margin-top: 20px;">
                    <i class="fas fa-history"></i> 请求历史
                </div>
                
                <ul class="history-list" id="historyList">
                    <!-- 历史记录将通过JavaScript动态加载 -->
                </ul>
                
                <div class="clear-history">
                    <button onclick="clearHistory()"><i class="fas fa-trash"></i> 清空历史</button>
                </div>
            </div>
            
            <div class="main-content">
                <div class="panel">
                    <div class="form-group">
                        <label for="requestUrl">请求URL</label>
                        <div style="display: flex; gap: 10px;">
                            <select id="requestMethod" class="form-control" style="flex: 0 0 100px;">
                                <option value="GET">GET</option>
                                <option value="POST">POST</option>
                                <option value="PUT">PUT</option>
                                <option value="DELETE">DELETE</option>
                            </select>
                            <input type="text" id="requestUrl" class="form-control" placeholder="/function_name">
                        </div>
                    </div>
                </div>
                
                <div class="panel">
                    <div class="request-tabs">
                        <div class="tab active" onclick="switchTab('params')">查询参数</div>
                        <div class="tab" onclick="switchTab('headers')">请求头</div>
                        <div class="tab" onclick="switchTab('body')">请求体</div>
                    </div>
                    
                    <div class="tab-content active" id="paramsTab">
                        <table class="key-value-table" id="paramsTable">
                            <thead>
                                <tr>
                                    <th width="40%">参数名</th>
                                    <th width="55%">值</th>
                                    <th width="5%"></th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr>
                                    <td><input type="text" placeholder="参数名" class="param-key"></td>
                                    <td><input type="text" placeholder="值" class="param-value"></td>
                                    <td><button onclick="removeRow(this)"><i class="fas fa-trash"></i></button></td>
                                </tr>
                            </tbody>
                        </table>
                        <button class="add-row-btn" onclick="addRow('paramsTable')">
                            <i class="fas fa-plus"></i> 添加参数
                        </button>
                    </div>
                    
                    <div class="tab-content" id="headersTab">
                        <table class="key-value-table" id="headersTable">
                            <thead>
                                <tr>
                                    <th width="40%">头名称</th>
                                    <th width="55%">值</th>
                                    <th width="5%"></th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr>
                                    <td><input type="text" placeholder="头名称" class="header-key"></td>
                                    <td><input type="text" placeholder="值" class="header-value"></td>
                                    <td><button onclick="removeRow(this)"><i class="fas fa-trash"></i></button></td>
                                </tr>
                            </tbody>
                        </table>
                        <button class="add-row-btn" onclick="addRow('headersTable')">
                            <i class="fas fa-plus"></i> 添加头
                        </button>
                    </div>
                    
                    <div class="tab-content" id="bodyTab">
                        <textarea id="requestBody" class="json-editor" placeholder='{"key": "value"}'></textarea>
                    </div>
                </div>
                
                <button class="submit-btn" onclick="sendRequest()">
                    <i class="fas fa-paper-plane"></i> 发送请求
                </button>
                
                <div class="loading" id="loading">
                    <div class="spinner"></div>
                    <p>正在发送请求...</p>
                </div>
                
                <div class="response-container" id="responseContainer" style="display: none;">

                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        const API_BASE_URL = 'http://localhost:5476/api/v1';
        
        // 初始化页面
        document.addEventListener('DOMContentLoaded', function() {
            loadFunctions();
            loadHistory();
        });
        
        // 加载函数列表
        async function loadFunctions() {
            try {
                const response = await fetch(`${API_BASE_URL}/functions`);
                const data = await response.json();
                
                const functionList = document.getElementById('functionList');
                
                if (data.functions && data.functions.length > 0) {
                    data.functions.forEach(funcName => {
                        const li = document.createElement('li');
                        li.className = 'function-item';
                        li.innerHTML = `<i class="fas fa-code"></i> ${funcName}`;
                        li.onclick = function() {
                            selectFunction(funcName, this);
                        };
                        functionList.appendChild(li);
                    });
                    
                    // 默认选择第一个函数
                    if (data.functions.length > 0) {
                        const firstItem = functionList.querySelector('.function-item');
                        firstItem.click();
                    }
                } else {
                    functionList.innerHTML = `
                        <div class="no-functions">
                            <i class="fas fa-folder-open"></i>
                            <p>没有找到可用的Lambda函数</p>
                        </div>
                    `;
                }
            } catch (error) {
                console.error('加载函数列表失败:', error);
            }
        }
        
        // 选择函数
        function selectFunction(funcName, element) {
            // 更新UI
            document.querySelectorAll('.function-item').forEach(item => {
                item.classList.remove('active');
            });
            element.classList.add('active');
            
            // 更新URL
            document.getElementById('requestUrl').value = `/${funcName}`;
        }
        
        // 切换标签页
        function switchTab(tabId) {
            document.querySelectorAll('.tab').forEach(tab => {
                tab.classList.remove('active');
            });
            document.querySelectorAll('.tab-content').forEach(content => {
                content.classList.remove('active');
            });
            
            event.currentTarget.classList.add('active');
            document.getElementById(`${tabId}Tab`).classList.add('active');
        }
        
        // 切换响应标签页
        function switchResponseTab(tabId) {
            document.querySelectorAll('.response-tab').forEach(tab => {
                tab.classList.remove('active');
            });
            document.querySelectorAll('.response-tab-content').forEach(content => {
                content.classList.remove('active');
            });
            
            event.currentTarget.classList.add('active');
            document.getElementById(`${tabId}Tab`).classList.add('active');
        }
        
        // 添加行
        function addRow(tableId) {
            const table = document.getElementById(tableId);
            const tbody = table.querySelector('tbody');
            const newRow = document.createElement('tr');
            
            let keyClass, valueClass;
            if (tableId === 'paramsTable') {
                keyClass = 'param-key';
                valueClass = 'param-value';
            } else {
                keyClass = 'header-key';
                valueClass = 'header-value';
            }
            
            newRow.innerHTML = `
                <td><input type="text" placeholder="${tableId === 'paramsTable' ? '参数名' : '头名称'}" class="${keyClass}"></td>
                <td><input type="text" placeholder="值" class="${valueClass}"></td>
                <td><button onclick="removeRow(this)"><i class="fas fa-trash"></i></button></td>
            `;
            
            tbody.appendChild(newRow);
        }
        
        // 删除行
        function removeRow(button) {
            const row = button.closest('tr');
            row.remove();
        }
        
        // 发送请求
        async function sendRequest() {
            const method = document.getElementById('requestMethod').value;
            let url = document.getElementById('requestUrl').value;

            if (!url) {
                alert('请输入请求URL');
                return;
            }
            
            // 收集查询参数
            const params = {};
            document.querySelectorAll('.param-key').forEach((keyInput, index) => {
                const valueInput = document.querySelectorAll('.param-value')[index];
                if (keyInput.value) {
                    params[keyInput.value] = valueInput.value;
                }
            });
            
            // 如果有查询参数，添加到URL
            const queryString = Object.entries(params)
                .filter(([key, value]) => key && value)
                .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
                .join('&');
            
            if (queryString) {
                url += (url.includes('?') ? '&' : '?') + queryString;
            }
            
            // 收集请求头
            const headers = {};
            document.querySelectorAll('.header-key').forEach((keyInput, index) => {
                const valueInput = document.querySelectorAll('.header-value')[index];
                if (keyInput.value) {
                    headers[keyInput.value] = valueInput.value;
                }
            });
            
            // 设置Content-Type为application/json（如果有请求体）
            let body = document.getElementById('requestBody').value;
            if (body && method !== 'GET') {
                headers['Content-Type'] = 'application/json';
                
                // 尝试解析JSON，如果无效则使用原始文本
                try {
                    body = JSON.parse(body);
                } catch (e) {
                    // 保持原始文本
                }
            }
            
            // 显示加载状态
            document.getElementById('loading').style.display = 'block';
            document.getElementById('responseContainer').style.display = 'none';
            
            try {
                const options = {
                    method: method,
                    headers: headers
                };
                
                if (body && method !== 'GET') {
                    options.body = JSON.stringify(body);
                }
                
                const response = await fetch(`${API_BASE_URL}${url}`, options);
                const responseData = await response.text();
                
                // 保存到历史记录
                saveToHistory(method, url, options.body, response.status);
                
                // 显示响应
                displayResponse(response.status, responseData, response.headers);
                
            } catch (error) {
                displayResponse(0, `请求失败: ${error.message}`, new Headers());
            } finally {
                document.getElementById('loading').style.display = 'none';
            }
        }
        
        // 显示响应
        function displayResponse(status, body, headers) {
            const responseContainer = document.getElementById('responseContainer');
            const statusBadge = document.getElementById('statusBadge');
            const responseBody = document.getElementById('responseBody');
            const responseHeaders = document.getElementById('responseHeaders');
            
            responseContainer.style.display = 'block';
            
            // 设置状态
            if (status >= 200 && status < 300) {
                statusBadge.className = 'status-badge status-success';
                statusBadge.textContent = `成功 ${status}`;
            } else if (status >= 400) {
                statusBadge.className = 'status-badge status-error';
                statusBadge.textContent = `错误 ${status}`;
            } else {
                statusBadge.className = 'status-badge status-error';
                statusBadge.textContent = `请求失败`;
            }
            
            // 设置响应体
            try {
                const parsedBody = JSON.parse(body);
                responseBody.textContent = JSON.stringify(parsedBody, null, 2);
            } catch (e) {
                responseBody.textContent = body;
            }
            
            // 设置响应头
            let headersText = '';
            headers.forEach((value, key) => {
                headersText += `${key}: ${value}\n`;
            });
            responseHeaders.textContent = headersText;
            
            // 默认显示响应标签页
            switchResponseTab('response');
        }
        
        // 保存到历史记录
        function saveToHistory(method, url, body, status) {
            const history = JSON.parse(localStorage.getItem('lambdaRequestHistory') || '[]');
            
            // 限制历史记录数量
            if (history.length >= 50) {
                history.pop();
            }
            
            history.unshift({
                method: method,
                url: url,
                body: body,
                status: status,
                timestamp: new Date().toISOString()
            });
            
            localStorage.setItem('lambdaRequestHistory', JSON.stringify(history));
            loadHistory();
        }
        
        // 加载历史记录
        function loadHistory() {
            const historyList = document.getElementById('historyList');
            const history = JSON.parse(localStorage.getItem('lambdaRequestHistory') || '[]');
            
            historyList.innerHTML = '';
            
            if (history.length === 0) {
                historyList.innerHTML = '<li style="padding: 15px; color: #64748b; text-align: center;">没有历史记录</li>';
                return;
            }
            
            history.forEach(item => {
                const li = document.createElement('li');
                li.className = 'history-item';
                li.onclick = () => loadHistoryItem(item);
                
                // 格式化时间
                const date = new Date(item.timestamp);
                const timeStr = `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
                
                li.innerHTML = `
                    <span class="history-method method-${item.method.toLowerCase()}">${item.method}</span>
                    <span class="history-url">${item.url}</span>
                    <span class="history-time">${timeStr}</span>
                `;
                
                historyList.appendChild(li);
            });
        }
        
        // 加载历史记录项
        function loadHistoryItem(item) {
            document.getElementById('requestMethod').value = item.method;
            document.getElementById('requestUrl').value = item.url.split('?')[0];
            
            // 解析查询参数
            const urlParts = item.url.split('?');
            if (urlParts.length > 1) {
                const paramsTable = document.getElementById('paramsTable');
                const tbody = paramsTable.querySelector('tbody');
                tbody.innerHTML = '';
                
                const params = new URLSearchParams(urlParts[1]);
                params.forEach((value, key) => {
                    const row = document.createElement('tr');
                    row.innerHTML = `
                        <td><input type="text" placeholder="参数名" class="param-key" value="${key}"></td>
                        <td><input type="text" placeholder="值" class="param-value" value="${value}"></td>
                        <td><button onclick="removeRow(this)"><i class="fas fa-trash"></i></button></td>
                    `;
                    tbody.appendChild(row);
                });
            }
            
            // 如果有请求体，设置到请求体编辑器
            if (item.body) {
                try {
                    const parsedBody = JSON.parse(item.body);
                    document.getElementById('requestBody').value = JSON.stringify(parsedBody, null, 2);
                } catch (e) {
                    document.getElementById('requestBody').value = item.body;
                }
            }
            
            // 切换到参数标签页
            switchTab('params');
        }
        
        // 清空历史记录
        function clearHistory() {
            if (confirm('确定要清空所有历史记录吗？')) {
                localStorage.removeItem('lambdaRequestHistory');
                loadHistory();
            }
        }
    </script>
</body>
</html>